package edu.taru.aspectj;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

public class LogAspectj {

    //声明sl4j 日志
    private static Logger logger = LoggerFactory.getLogger(LogAspectj.class);

    /**
     * 之前
     */
    public void beforeMethod(JoinPoint joinPoint){
        //切点，获取方法名
        String methodName = joinPoint.getSignature().getName();
        //切点，获取方法参数
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        //打印日志
        logger.info("{}—准备进去；方法名:{}；方法参数:{}",LocalDateTime.now(),methodName,args);
    }
    /**
     * 之后
     */
    public void afterMethod(JoinPoint joinPoint){
        //切点，获取方法名
        String methodName = joinPoint.getSignature().getName();
        logger.info("{}—:已经进去之后;方法名:{}。",LocalDateTime.now(),methodName);
    }
    /**
     * 返回
     */
    public Object afterReturnMethod(JoinPoint joinPoint,Object result){
        //切点，获取方法名
        String methodName = joinPoint.getSignature().getName();
        logger.info("{}—:返回;方法名:{};返回结果:{};。",LocalDateTime.now(),methodName,"end.result<"+result+">");
        return result;
    }
    /**
     * 异常
     */
    public void afterThrowingMethod(JoinPoint joinPoint,Exception ex){
        //切点，获取方法名
        String methodName = joinPoint.getSignature().getName();
        logger.info("{}—:出现异常;方法名:{};异常信息:{};。",LocalDateTime.now(),methodName,"<"+ex+">");
    }
    /**
     * 环绕通知(需要携带类型为ProceedingJoinPoint类型的参数)
     * 环绕通知包含前置、后置、返回、异常通知；ProceedingJoinPoin 类型的参数可以决定是否执行目标方法
     * 且环绕通知必须有返回值，返回值即目标方法的返回值
     * @param point
     */
    public Object aroundMethod(ProceedingJoinPoint point){
        Object result = null;
        String methodName = point.getSignature().getName();
        try {
            //前置通知
            logger.info("{}—环绕通知—方法名:{};方法参数:{}。",LocalDateTime.now(),methodName,"<"+ Arrays.asList(point.getArgs())+">");
            //执行目标方法
            result = point.proceed();
            //返回通知
            logger.info("{}—环绕通知—方法名:{};返回结果:{}。",LocalDateTime.now(),methodName,"<"+ result+">");
        } catch (Throwable e) {
            //异常通知
            logger.info("{}—环绕通知—方法名:{};异常信息:{}。",LocalDateTime.now(),methodName,"<"+ e+">");
            throw new RuntimeException(e);
        }
        //后置通知
        logger.info("{}—环绕通知—方法名:{}；end。",LocalDateTime.now(),methodName);
        return result;
    }
}
